{
 "cells": [
  {
   "attachments": {},
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# A step-by-step look at the Simulation class\n",
    "The simplest way to solve a model is to use the `Simulation` class. This automatically processes the model (setting of parameters, setting up the mesh and discretisation, etc.) for you, and provides built-in functionality for solving and plotting. Changing things such as parameters in handled by passing options to the `Simulation`, as shown in the [Getting Started](../getting_started/tutorial-1-how-to-run-a-model.ipynb) guides, [example notebooks](../../index.rst) and [documentation](https://docs.pybamm.org/en/latest/source/api/simulation.html).\n",
    "\n",
    "In this notebook we show how to solve a model using a `Simulation` and compare this to manually handling the different stages of the process, such as setting parameters, ourselves step-by-step."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [],
   "source": [
    "%pip install \"pybamm[plot,cite]\" -q    # install PyBaMM if it is not installed\n",
    "import pybamm"
   ]
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Simulation\n",
    "The easiest way to get started is to pick a model and create a simulation using that model. For simplicity, we'll use the SPM with all the default options here. "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [],
   "source": [
    "model = pybamm.lithium_ion.SPM()\n",
    "simulation = pybamm.Simulation(model)"
   ]
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "The simulation can then be solved, passing a time interval (in seconds) to integrate over"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "<pybamm.solvers.solution.Solution at 0x2698c4bb3d0>"
      ]
     },
     "execution_count": 3,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "simulation.solve([0, 3600])"
   ]
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "and the results plotted"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "application/vnd.jupyter.widget-view+json": {
       "model_id": "8a1f718b449e4d758b42191015d1a26c",
       "version_major": 2,
       "version_minor": 0
      },
      "text/plain": [
       "interactive(children=(FloatSlider(value=0.0, description='t', max=1.0, step=0.01), Output()), _dom_classes=('w…"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "text/plain": [
       "<pybamm.plotting.quick_plot.QuickPlot at 0x2698c4da370>"
      ]
     },
     "execution_count": 4,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "simulation.plot()"
   ]
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Simple!"
   ]
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "A GIF of the simulation can also be obtained"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [],
   "source": [
    "# using less number of images in the example\n",
    "# for a smoother GIF use more images\n",
    "simulation.create_gif(\n",
    "    number_of_images=5, duration=0.2, output_filename=\"simulation.gif\"\n",
    ")"
   ]
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Displaying the GIF using markdown -\n",
    "![plot](https://user-images.githubusercontent.com/74055102/142718167-ef119372-1e9b-4d5c-9ccb-8689b2aad391.gif)"
   ]
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Processing the model step-by-step\n",
    "One way of gaining more control over the simulation processing is by passing options, as outlined in the [documentation](https://docs.pybamm.org/en/latest/source/api/simulation.html). However, you can also process the model step-by-step yourself. A detailed example of this can be found in the [SPM notebook](../models/SPM.ipynb), but here we outline the basic steps.\n",
    "\n",
    "First we pick a model"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [],
   "source": [
    "model = pybamm.lithium_ion.SPM()"
   ]
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Next we must set up the geometry. We'll use the default geometry for the SPM. In all of the following steps we will also use the default settings provided by the model. For a look at changing these options, see the [change settings](../change-settings.ipynb) notebook."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [],
   "source": [
    "geometry = model.default_geometry"
   ]
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Both the model and geometry depend on parameters (such as the electrode thickness, or diffusivity). We'll use the default model parameters"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [],
   "source": [
    "param = model.default_parameter_values"
   ]
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Now that we have picked our parameters we can \"process\" the model and geometry. This just means we look through the model and geometry for any parameter symbols and replace them with the numeric values (or functions, in the case of parameters that have functional dependence) defined by our parameter values."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {},
   "outputs": [],
   "source": [
    "param.process_model(model)\n",
    "param.process_geometry(geometry)"
   ]
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Next we must create a mesh on which to solve the discretised equations. This not only depends on the geometry, but also on the type of submesh (e.g. uniformly space) and number of mesh points to use. "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {},
   "outputs": [],
   "source": [
    "mesh = pybamm.Mesh(geometry, model.default_submesh_types, model.default_var_pts)"
   ]
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Now that we have defined a mesh we can discretise our model. In order to do so we must choose a spatial method. The default for the SPM is the Finite Volume Method. We first define a discretisation, which depends on the mesh and spatial method, and then use this to process our model. This turns the variables in the models into a `StateVector`, and replaces spatial operators with matrix-vector multiplications, ready to be passed to a time stepping algorithm."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "<pybamm.models.full_battery_models.lithium_ion.spm.SPM at 0x2699d43f100>"
      ]
     },
     "execution_count": 11,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "disc = pybamm.Discretisation(mesh, model.default_spatial_methods)\n",
    "disc.process_model(model)"
   ]
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Finally, we pick a solver to step the problem forward in time. We'll use the default ODE solver for the SPM"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {},
   "outputs": [],
   "source": [
    "solver = model.default_solver"
   ]
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "We then integrate in time using the `solve` command, as with the simulation. Note that we now have to pass the model object to the `solve` command, and that we return the solution object so that we can interact with it later."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "metadata": {},
   "outputs": [],
   "source": [
    "solution = solver.solve(model, [0, 3600])"
   ]
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "We can create the default slider plot by passing the solution object to the `dynamic_plot` method"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "application/vnd.jupyter.widget-view+json": {
       "model_id": "daf8dc7b0f524c3eb32b6a3d28f978de",
       "version_major": 2,
       "version_minor": 0
      },
      "text/plain": [
       "interactive(children=(FloatSlider(value=0.0, description='t', max=1.0, step=0.01), Output()), _dom_classes=('w…"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "text/plain": [
       "<pybamm.plotting.quick_plot.QuickPlot at 0x2699064c760>"
      ]
     },
     "execution_count": 14,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "pybamm.dynamic_plot(solution)"
   ]
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## References\n",
    "\n",
    "The relevant papers for this notebook are:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[1] Joel A. E. Andersson, Joris Gillis, Greg Horn, James B. Rawlings, and Moritz Diehl. CasADi – A software framework for nonlinear optimization and optimal control. Mathematical Programming Computation, 11(1):1–36, 2019. doi:10.1007/s12532-018-0139-4.\n",
      "[2] Charles R. Harris, K. Jarrod Millman, Stéfan J. van der Walt, Ralf Gommers, Pauli Virtanen, David Cournapeau, Eric Wieser, Julian Taylor, Sebastian Berg, Nathaniel J. Smith, and others. Array programming with NumPy. Nature, 585(7825):357–362, 2020. doi:10.1038/s41586-020-2649-2.\n",
      "[3] Scott G. Marquis, Valentin Sulzer, Robert Timms, Colin P. Please, and S. Jon Chapman. An asymptotic derivation of a single particle model with electrolyte. Journal of The Electrochemical Society, 166(15):A3693–A3706, 2019. doi:10.1149/2.0341915jes.\n",
      "[4] Valentin Sulzer, Scott G. Marquis, Robert Timms, Martin Robinson, and S. Jon Chapman. Python Battery Mathematical Modelling (PyBaMM). Journal of Open Research Software, 9(1):14, 2021. doi:10.5334/jors.309.\n",
      "\n"
     ]
    }
   ],
   "source": [
    "pybamm.print_citations()"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.11.1"
  },
  "vscode": {
   "interpreter": {
    "hash": "a06befff6f507b2769436dc41c340f64f62afa83086a8cd273928f468e329d0b"
   }
  }
 },
 "nbformat": 4,
 "nbformat_minor": 4
}
